package de.tum.se.sudoku.logic;

import de.tum.se.sudoku.impl.Cell;
import de.tum.se.sudoku.impl.Grid;
import de.tum.se.sudoku.impl.VariableCell;

import java.util.LinkedList;

/**
 * The BruteForce way to solve a Sudoku.
 * 
 * The idea is the following. First the entire grid is scanned for
 * VariableCells. These cells are then put into a list, so we can focus each
 * iteration only on the changeable cells.
 * 
 * Then this list of cells is recursively changed. You could imagine the list as
 * a chain of values starting with 11111111 and are counted up with each
 * iteration. So the next loop the chain would look like this 11111112, 11111113
 * ... 11111119, 11111121
 * 
 * This is the BruteForce way to solve the Sudoku.
 * 
 * 
 * @author Oliver
 * 
 */
public class SolverBruteForce implements ISolver {

	@Override
	public Grid solve(Grid input) {

		Cell[][] cells = input.getCells();
		LinkedList<Cell> changeableCells = new LinkedList<Cell>();

		for (int i = 0; i < 9; i++) {
			for (int j = 0; j < 9; j++) {
				if (cells[i][j] instanceof VariableCell) {
					cells[i][j].setValue(1);
					changeableCells.add(cells[i][j]);
				}
			}
		}

		// Integer listLength = changeableCells.size();
		// Double combinations = Math.pow(9, listLength.doubleValue());
		// Integer counter = 0;
		// Double progress;

		while (!input.isValid()) {
			printListValues(changeableCells);
			bruteForceList(changeableCells);
			// counter++;
			// progress = (counter.doubleValue() / combinations) * 10000;
			// System.out.println(progress);
		}

		return input;
	}

	private int bruteForceList(LinkedList<Cell> cellList) {
		if (cellList.size() == 0) {
			return 1;
		} else {
			Cell cell;
			cell = cellList.pop();
			int originalValue = cell.getValue();
			int newValue = originalValue + bruteForceList(cellList);
			if (newValue < 10) {
				Cell newCell = new VariableCell(newValue);
				cellList.addFirst(newCell);
				return 0;
			} else {
				cell.setValue(1);
				cellList.addFirst(cell);
				return 1;
			}
		}
	}

	private void printListValues(LinkedList<Cell> changeableCells) {
		for (Cell cell : changeableCells) {
			System.out.print(cell.getValue() + " ");
		}
		System.out.println();
	}

}
